﻿using System.Collections.Generic;

namespace Gj
{
    public class FindPart : BasePart
    {
        private List<RealObject> _elementList;
        private ElementNotice _elementNotice;
        private List<BaseObject> _objectList;
        private ObjectNotice _objectNotice;
        private RealObject _self;

        public void Set(ElementNotice notice)
        {
            _elementNotice = notice;
        }

        public void Set(ObjectNotice notice)
        {
            _objectNotice = notice;
        }


        public void Init(RealObject target)
        {
            _self = target;
        }

        public void Stop()
        {
            var entity = _self.GetEntity();
            var manager = ObjectService.EntityManager;
            manager.RemoveComponent<ViewHitsData>(entity);
            manager.RemoveComponent<CastViewData>(entity);
        }

        public void FindElement(float radius)
        {
            FindElement(radius, 360);
        }

        public List<RealObject> FindElement(float radius, float angle)
        {
            var entity = _self.GetEntity();
            var manager = ObjectService.EntityManager;
            if (_elementList == null)
                _elementList = new List<RealObject>();
            else
                _elementList.Clear();
            if (manager.HasComponent<ViewHitsData>(entity))
            {
                var castHitsDatas = manager.GetBuffer<ViewHitsData>(entity);
                if (castHitsDatas.Length > 0)
                    for (var i = 0; i < castHitsDatas.Length; i++)
                    {
                        var castHitsData = castHitsDatas[i];
                        if (manager.HasComponent<EntityData>(castHitsData.entity))
                        {
                            var element = ControlService.single.Get(castHitsData.entity);
                            if (element != null) _elementList.Add(element);
                        }
                    }

                manager.RemoveComponent<CastHitsData>(entity);
            }

            manager.AddComponentData(entity, new CastViewData
            {
                origin = _self.GetPosition(),
                direction = _self.GetRotation().eulerAngles,
                angle = angle,
                radius = radius
            });
            var elements = _elementList.ToArray();
            if (elements.Length > 0 && _elementNotice != null) _elementNotice.FindElement(elements);
            return _elementList;
        }

        public List<BaseObject> FindObject(float radius)
        {
            var entity = _self.GetEntity();
            var manager = ObjectService.EntityManager;
            if (_objectList == null)
                _objectList = new List<BaseObject>();
            else
                _objectList.Clear();

            var j = 0;
            if (manager.HasComponent<ViewHitsData>(entity))
            {
                var castHitsDatas = manager.GetBuffer<ViewHitsData>(entity);
                if (castHitsDatas.Length > 0)
                    for (var i = 0; i < castHitsDatas.Length; i++)
                    {
                        var castHitsData = castHitsDatas[i];
                        if (manager.HasComponent<UnknowData>(castHitsData.entity))
                        {
                            if (_objectList.Count > j)
                                _objectList[j].Replace(castHitsData.entity);
                            else
                                _objectList.Add(new BaseObject(castHitsData.entity));

                            j++;
                        }
                    }

                manager.RemoveComponent<CastHitsData>(entity);
            }

            manager.AddComponentData(entity, new CastViewData
            {
                origin = _self.GetPosition(),
                direction = _self.GetRotation().eulerAngles,
                angle = 360,
                radius = radius
            });
            if (_objectList.Count > j) _objectList.RemoveRange(j, _objectList.Count - j);
            var objects = _objectList.ToArray();
            if (objects.Length > 0 && _objectNotice != null) _objectNotice.FindObject(objects);
            return _objectList;
        }

        public interface ElementNotice
        {
            void FindElement(RealObject[] elements);
        }

        public interface ObjectNotice
        {
            void FindObject(BaseObject[] objects);
        }
    }
}